#include "netrunner.h"

#include "../wfnet.h"
#include "netrunnable.h"

#include <QtCore/QThreadPool>

using namespace wfnet;

NetRunner* netRunner = 0;

NetRunner* NetRunner::getInstance()
{
    if (netRunner == 0)
    {
        netRunner = new NetRunner();
    }

    return netRunner;
}

void NetRunner::destroy()
{
    delete netRunner;
    netRunner = 0;
}

void NetRunner::runNet(WfNet* net, int repetitions)
{
    QThreadPool* pool = QThreadPool::globalInstance();

    const int size = m_runningNets.size();
    if (size == 0 /*|| (size + pool->activeThreadCount() <
        pool->maxThreadCount())*/) // TODO: limited to one thread
    {
        NetRunnable* runnable = new NetRunnable(net, repetitions);
        m_runningNets[net] = runnable;

        connect(runnable->m_thread, SIGNAL(finished()),
            this, SLOT(onFinished()));
        connect(runnable->m_thread, SIGNAL(terminated()),
            this, SLOT(onTerminated()));

        m_terminateRequest = false;

        net->createNewJournal();

        runnable->start();
        QMetaObject::invokeMethod(runnable, "run", Qt::QueuedConnection);
    }
    else
    {
        // do nothing
    }
}

void NetRunner::pauseNet(WfNet* net)
{
    if (m_runningNets.contains(net))
    {
        NetRunnable* runnable = m_runningNets[net];

        // pause net
    }
}

void NetRunner::stopNet(WfNet* net)
{
    if (m_runningNets.contains(net))
    {
        NetRunnable* runnable = m_runningNets[net];

        m_terminateRequest = true;

        runnable->quit();
    }
}

QPointer<NetRunnable> NetRunner::getRunnable(WfNet* net) const
{
    NetRunnable* runnable = 0;

    if (m_runningNets.contains(net))
    {
        runnable = m_runningNets[net];
    }

    return runnable;
}

NetRunner::NetRunner() : QObject(),
    m_runningNets(),
    m_terminateRequest(false)
{

}

NetRunner::~NetRunner()
{
    foreach (NetRunnable* runnable, m_runningNets)
    {
        runnable->quit();
        m_runningNets.remove(runnable->m_net);
    }
}

void NetRunner::onFinished()
{
    NetRunnable* runnable = qobject_cast<NetRunnable *>(
        QObject::sender()->parent());

    if (runnable != 0)
    {
        if (!m_terminateRequest)
        {
            runnable->m_net->emitFinished();
        }

        m_runningNets.remove(runnable->m_net);
        runnable->deleteLater();
    }
}

void NetRunner::onTerminated()
{
    m_terminateRequest = true;

    NetRunnable* runnable = qobject_cast<NetRunnable *>(
        QObject::sender()->parent());

    if (runnable != 0)
    {
        m_runningNets.remove(runnable->m_net);
        runnable->deleteLater();
    }
}
